#include "glare.d3d11.RenderWindow.h"
#include "glare.d3d11.Driver.h"
#include "glare.core.Win32Window.h"
#include "glare.core.StringConverter.h"

namespace Glare {

	const string D3D11RenderWindow::OPTION_PRESENT_FLAGS = "PresentFlags";

	D3D11RenderWindow::D3D11RenderWindow(D3D11Driver* driver, PlatformWindow* platform_window) 
		: RenderWindow(platform_window)
		, _driver(driver)
		, _d3d_swapchain(NULL)
		// OPTIONS
		, _present_flags(0)
	{
		string psf_values[] = 
		{
			StringConverter::ToString((int)DXGI_PRESENT_DO_NOT_SEQUENCE),
			StringConverter::ToString((int)DXGI_PRESENT_TEST),
			StringConverter::ToString((int)DXGI_PRESENT_RESTART),
			//StringConverter::ToString(DXGI_PRESENT_DO_NOT_WAIT),
			//StringConverter::ToString(DXGI_PRESENT_RESTRICT_TO_OUTPUT),
			//StringConverter::ToString(DXGI_PRESENT_STEREO_PREFER_RIGHT),
			//StringConverter::ToString(DXGI_PRESENT_STEREO_TEMPORARY_MONO),
		};
		AddConfigOption(OPTION_PRESENT_FLAGS, "0", false, psf_values, 3, 
			"http://msdn.microsoft.com/en-us/library/windows/desktop/bb509554(v=vs.85).aspx");

		//AddConfigOption(OPTION_PRESENT_FLAGS, "0", false, {string()});
	}

	D3D11RenderWindow::~D3D11RenderWindow()
	{
		GLARE_SAFE_RELEASE(_d3d_rendertarget_view, "Error while releasing D3D RenderTargetView of RenderWindow");
		GLARE_SAFE_RELEASE(_d3d_backbuffer_texture, "Error while releasing D3D backbuffer Texture of RenderWindow");
		GLARE_SAFE_RELEASE(_d3d_swapchain, "Error while releasing DXGI swapchain of RenderWindow");
	}

	void D3D11RenderWindow::InitializeImpl()
	{
		Win32Window* w32_window = static_cast<Win32Window*>(GetPlatformWindow());

		HWND hwnd = w32_window->GetWindowHandle();

		DXGI_SWAP_CHAIN_DESC swap_chain_desc;
		ZeroMemory(&swap_chain_desc, sizeof(DXGI_SWAP_CHAIN_DESC));
		swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		swap_chain_desc.BufferDesc.Width = w32_window->GetWidth();
		swap_chain_desc.BufferDesc.Height = w32_window->GetHeight();
		swap_chain_desc.BufferDesc.RefreshRate.Numerator = 0;
		swap_chain_desc.BufferDesc.RefreshRate.Denominator = 0;
		swap_chain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
		swap_chain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		swap_chain_desc.SampleDesc.Count = 1;
		swap_chain_desc.SampleDesc.Quality = 0;
		swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swap_chain_desc.BufferCount = 1;
		swap_chain_desc.OutputWindow = hwnd;
		swap_chain_desc.Windowed = !IsFullscreen();
		swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
		swap_chain_desc.Flags = 0;

		GLARE_THROW(_driver->GetDXGIFactory()->CreateSwapChain(_driver->GetDXGIDevice(), &swap_chain_desc, &_d3d_swapchain), "Error while creating DXGI swapchain for RenderWindow");
		GLARE_THROW(_d3d_swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&_d3d_backbuffer_texture), "Error while getting backbuffer texture from D3D swapchain");
		GLARE_THROW(_driver->GetD3DDevice()->CreateRenderTargetView(_d3d_backbuffer_texture, NULL, &_d3d_rendertarget_view), "Error while getting rendertarget view from D3D backbuffer texture");
	}

	void D3D11RenderWindow::Present()
	{
		_d3d_swapchain->Present(GetPresentSyncInterval(), _present_flags);
	}
	
	void D3D11RenderWindow::SetFullscreenImpl(const bool& fullscreen)
	{
		throw Exception("The method or operation is not implemented.");
	}

	void D3D11RenderWindow::SetOptionImpl(const string& name, const string& value)
	{
		if (name == OPTION_PRESENT_FLAGS)
			_present_flags = StringConverter::ParseUint(value);
	}

	RenderTarget::Interface* D3D11RenderWindow::_GetInterface()
	{
		return this;
	}

	Driver* D3D11RenderWindow::GetDriver() const
	{
		return _driver;
	}

	ID3D11RenderTargetView* D3D11RenderWindow::GetD3DRenderTargetView() const
	{
		return _d3d_rendertarget_view;
	}

}
